package com.ylz.sjzx.sio.sdk.client.core;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@Slf4j
public class ImAllocator {

    /**
     * 控制返回消息是发送的两倍 如果配置了 io.netty.allocator.numDirectArenas 否则一样
     */
    private static final BlockingQueue<ByteBuf> bufferQueue = new ArrayBlockingQueue<ByteBuf>(100);

    private static final BlockingQueue<ByteBuf> toCleanQueue = new LinkedBlockingQueue<ByteBuf>();

    private static final int TO_CLEAN_SIZE = 100;

    private static final long CLEAN_PERIOD = 500;

    static {
        Thread thread = new Thread(new AllocThread(), "im-allocator");
        thread.setDaemon(true);
        thread.start();

    }

    @SneakyThrows
    public static ByteBuf alloc(boolean isMsg) {
        if (isMsg) {
            return Unpooled.directBuffer();
        } else {
            return bufferQueue.take();
        }
    }

    public static void forceRelease(ByteBuf buffer) {
        boolean flag = false;
        while (!flag) {
            flag = ReferenceCountUtil.release(buffer);
        }
    }

    public static void release(ByteBuf buf) {
        toCleanQueue.add(buf);
    }

    private static class AllocThread implements Runnable {

        @Override

        public void run() {

            long lastCleanTime = System.currentTimeMillis();

            while (IMNioBase.isGlobalRun) {
                //添加buffer池子到队列
                try {
                    if (bufferQueue.size() < 100) {
                        ByteBuf buffer = Unpooled.directBuffer();
                        //确保是本线程释放
                        bufferQueue.put(buffer);
                    }
                    //释放buffer
                    if (toCleanQueue.size() > TO_CLEAN_SIZE
                            || System.currentTimeMillis() - lastCleanTime > CLEAN_PERIOD) {
                        final List<ByteBuf> toClean = new ArrayList<ByteBuf>(toCleanQueue.size());
                        toCleanQueue.drainTo(toClean);
                        for (ByteBuf buffer : toClean) {
                            ReferenceCountUtil.release(buffer);
                            log.debug("");
                        }
                        lastCleanTime = System.currentTimeMillis();
                    }
                    if (bufferQueue.size() > 90) {
                        Thread.sleep(5);
                    }
                } catch (InterruptedException e) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    log.error("buffer 池子异常", e);
                }
            }
        }
    }

}
